package cn.yangliu.jwt.service;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.TransactionStatus;

import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;

/**
 * @author 杨柳
 * @contact QQ: 574789490
 * @date 2019-04-18 10:38
 */
public interface JpaService<T, ID> {

    T execute(Function<TransactionStatus, T> function);

    List<T> findAll();

    List<T> findAll(Sort sort);

    Page<T> findAll(Pageable pageable);

    List<T> findAllById(Iterable<ID> ids);

    long count();

    void deleteById(ID id);

    void delete(T entity);

    void deleteAll(Iterable<? extends T> iterable);

    void deleteAll();

    T save(T entity);

    List<T> saveAll(Iterable<T> entities);

    Optional<T> findById(ID id);

    boolean existsById(ID id);

    T saveAndFlush(T entity);

    void deleteInBatch(Iterable<T> entities);

    void deleteAllInBatch();

    T getOne(ID id);

    Optional<T> findOne(T queryPojo);

    Iterable<T> findAll(T queryPojo);

    Iterable<T> findAll(T queryPojo, Sort sort);

    Page<T> findAll(T queryPojo, Pageable pageable);

    long count(T queryPojo);

    boolean exists(T queryPojo);

    default Specification<T> build(T queryPojo) {

        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (Objects.isNull(queryPojo)) {
                return cb.and(predicates.toArray(new Predicate[]{}));
            }
            try {
                Class<?> clazz = queryPojo.getClass();
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field field : declaredFields) {

                    //判断是不是静态属性
                    if (Modifier.isStatic(field.getModifiers())) {
                        continue;
                    }
                    boolean flag = field.isAccessible();
                    if (!flag) {
                        field.setAccessible(true);
                    }
                    Object value = field.get(queryPojo);

                    if (!flag) {
                        field.setAccessible(false);
                    }
                    if (Objects.isNull(value)) {
                        continue;
                    }
                    String fieldName = field.getName();

                    Path<?> path = root.get(fieldName);
                    Predicate predicate = cb.equal(path, value);
                    predicates.add(predicate);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            return cb.and(predicates.toArray(new Predicate[]{}));
        };
    }
}
